import pytest
import random
import string

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QApplication, QDialogButtonBox

from RBK.Model.db import Database
from RBK.View.MainWindow import MainWindow
from RBK.View.NewDialog import NewDialog
from RBK.Model.Functions import runQuery, isError


@pytest.fixture(scope='module', params=[(0, 'Actions'), \
                                        (1, 'Currencies'), \
                                        (2, 'Character') \
                                       ])
def datatypes(request):
    return request.param

@pytest.fixture(scope='module', params=['Struct', 'Data'])
def tabletypes(request):
    return request.param


@pytest.fixture(scope='module', params=['Name', \
                                        'Rulebook PDF Destination', \
                                        'Character Sheet Field' \
                                        ])
def dataFieldIndices(request):
    return request.param


@pytest.fixture(scope='module', params=[('Field Name', ('Name', \
                                                'Rulebook PDF Destination', \
                                                'Character Sheet Field')),
                                         ('Type', 'Text'), \
                                         ('Constraints', 'maxLength(50)'), \
                                         ('User Editable?', 'False') \
                                        ])
def structFieldIndices(request):
    return request.param


@pytest.fixture(scope='module')
def testRulebook(db):
    cr = runQuery(db.rulebooks, ('SELECT * FROM Rulebooks WHERE GameName = "Tests" AND Core = "False"'))
    if not isError(cr):
        return cr.getValue()[0]
    else:
        qt_api.qError('Unable to find a core Rulebook.  If you have not run \
                    the NewCoreRulebook test yet, please run that test first.')
        return QSqlRecord()


@pytest.fixture(scope='module')
def game(testRulebook):
    return testRulebook.value('GameName')


@pytest.fixture(scope='module')
def version(testRulebook):
    return testRulebook.value('GameVersion')


@pytest.fixture(scope='module')
def rbk(testRulebook):
    return testRulebook.value('RulebookName')


@pytest.fixture(scope='module')
def core(testRulebook):
    return testRulebook.value('Core')


@pytest.fixture(scope='module')
def corerbk(testRulebook):
    return testRulebook.value('CoreRulebook')


@pytest.fixture(scope='module')
def corehash(testRulebook):
    return testRulebook.value('CoreRulebookHash')


@pytest.fixture(scope='module')
def db():
    database = Database()
    yield database
    database.closeRulebook()


@pytest.fixture
def window(db):
    window = MainWindow(db)
    return window




def openDialogTitle(bot, win):
    assert win.openDialog.windowTitle() == 'Open Rulebook...'
    bot.mouseClick(win.openDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def openDialogGameDefault(bot, win):
    assert not win.openDialog.game.currentText()
    bot.mouseClick(win.openDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def openDialogGameExists(bot, win, g):
    assert win.openDialog.game.findText(g) > -1
    bot.mouseClick(win.openDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def openDialogVersionDefault(bot, win):
    assert not win.openDialog.version.currentText()
    bot.mouseClick(win.openDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def openDialogVersionExists(bot, win, v):
    assert win.openDialog.version.findText(v)
    bot.mouseClick(win.openDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def openDialogRulebookNameDefault(bot, win):
    assert not win.openDialog.rbkname.currentText()
    bot.mouseClick(win.openDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def openDialogRulebookNameExists(bot, win, r):
    assert win.openDialog.rbkname.findText(r)
    bot.mouseClick(win.openDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def openRulebook(bot, win, g, v, r):
    win.openDialog.game.setCurrentText(g)
    win.openDialog.version.setCurrentText(v)
    win.openDialog.rbkname.setCurrentText(r)

    bot.mouseClick(win.openDialog.buttons.button(QDialogButtonBox.Ok), \
                   Qt.LeftButton)


@pytest.fixture(scope='module', \
                params=[openDialogTitle,
                        openDialogGameDefault,
                        openDialogVersionDefault,
                        openDialogRulebookNameDefault,
                        openRulebook])
def test(request):
    return request.param


# openDialog is meant to be accepted/rejected by each test, so returned, not yielded.
def test_openDialogTests(qtbot, window, game, version, rbk, test):
    def pauseTest():
        while window.openDialog is None:
            QApplication.processEvents()
        if(test==openRulebook or test==openDialogRulebookNameExists):
            test(qtbot, window, game, version, rbk)
        elif(test==openDialogGameExists):
            test(qtbot, window, game)
        elif(test==openDialogVersionExists):
            test(qtbot, window, game, version)
        else:
            test(qtbot, window)

    window.show()
    qtbot.addWidget(window)
    QTimer.singleShot(500, pauseTest)
    qtbot.keyClick(window, Qt.Key_O, Qt.ControlModifier, delay=1)


##########################
#
# Rulebook Table
#
##########################

def test_RulebookTable(db):
        assert 'Rulebook' in db.models

def test_RulebookHasGameName(db, game):
    gamename = db.models['Rulebook'].record(0).value('GameName')
    assert gamename == game

def test_RulebookHasGameVersion(db, version):
    gameversion = db.models['Rulebook'].record(0).value('GameVersion')
    assert gameversion == version

def test_RulebookHasRulebookName(db, rbk):
    gamerbkname = db.models['Rulebook'].record(0).value('RulebookName')
    assert gamerbkname == rbk

# For Core, should be True
def test_RulebookHasCore(db, core):
    iamcore = db.models['Rulebook'].record(0).value('Core')
    assert iamcore == core

# For Core, should be empty string
def test_RulebookHasCoreRulebook(db, corerbk):
    gamecorerbk = db.models['Rulebook'].record(0).value('CoreRulebook')
    assert gamecorerbk == corerbk

# For Core, should be empty string
def test_RulebookHasCoreRulebookHash(db, corehash):
    gamecorehash = db.models['Rulebook'].record(0).value('CoreRulebookHash')
    assert gamecorehash == corehash


##########################
#
# DataTypes Table
#
##########################

def test_DataTypesTableExists(db, datatypes):
    assert 'DataTypes' in db.models

def test_DataTypeFound(db, datatypes):
    assert db.models['DataTypes'].record(datatypes[0]).value('DataType') == \
                                                                  datatypes[1]


##########################
#
# Struct Tables
#
##########################

def tablename(tt, dt):
    return tt + ' ' + dt

def test_OtherTableExists(db, tabletypes, datatypes):
    assert tablename(tabletypes, datatypes[1]) in db.models

def test_StructColumnCount(db, datatypes):
    assert db.models[tablename('Struct', datatypes[1])].columnCount() == 4

def test_StructRowCount(db, datatypes):
    assert db.models[tablename('Struct', datatypes[1])].rowCount() == 3

def test_StructNameFieldExists(db, datatypes, structFieldIndices):
    assert db.models[tablename('Struct', datatypes[1])].fieldIndex(structFieldIndices[0]) > -1

def test_RowsExists(db, datatypes, structFieldIndices):
    if structFieldIndices[0]=='Field Name':
        assert db.models[tablename('Struct', datatypes[1])].record( \
                        datatypes[0]).value(structFieldIndices[0]) == \
                        structFieldIndices[1][datatypes[0]]
    else:
        assert db.models[tablename('Struct', datatypes[1])].record( \
                        datatypes[0]).value(structFieldIndices[0]) == \
                        structFieldIndices[1]


##########################
#
# Data Tables
#
##########################

def test_DataColumnCount(db, datatypes):
    assert db.models[tablename('Data', datatypes[1])].columnCount() == 3

def test_DataRowcount(db, datatypes):
    assert db.models[tablename('Data', datatypes[1])].rowCount() == 0

def test_DataNameFieldExists(db, datatypes, dataFieldIndices):
    assert db.models[tablename('Data', datatypes[1])].fieldIndex( \
                                                        dataFieldIndices) > -1
